package cc.chinagps.gateway.util;

import cc.chinagps.gateway.client.packet.BasePacket;
import cc.chinagps.gateway.client.packet.ObdSignature;
import cc.chinagps.gateway.client.session.ISession;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

@Slf4j
public class CommonUtils {
    public static void msgAck(BasePacket basePacket, ISession session) throws Exception {
        msgAck(basePacket, session, new byte[0]);
    }

    public static void msgAck(BasePacket basePacket, ISession session, byte[] responseData) throws Exception {
        basePacket.setMsgBody(responseData);
        session.sendData(basePacket.encode());
    }

    public static void msgAck(BasePacket basePacket, byte responseMsgId, ISession session, byte[] responseData) throws Exception {
        basePacket.setMsgId(responseMsgId);
        basePacket.setMsgBody(responseData);
        session.sendData(basePacket.encode());
    }

    public static boolean verifySignature(byte[] data, ObdSignature obdSignature, String publicKey, String chipId) throws Exception {
        byte[] plainText = new byte[data.length - obdSignature.getDataLen()];
        System.arraycopy(data, 0, plainText, 0, plainText.length);

        byte[] signature = ByteUtils.concatenate(obdSignature.getRBytes(), obdSignature.getSBytes());
        return Sm2Util.verify(plainText, "04" + publicKey, signature, chipId);
    }

    public static String getFillZero(int zeroLen) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < zeroLen; i++) {
            sb.append("0");
        }
        return sb.toString();
    }

    public static String getRandomString(int length) {
        String str = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(str.length());
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

    public String getRandomCode(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(str.length());
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 可以指定某个位置是a-z、A-Z或是0-9
     *
     * @param length
     * @return
     */
    public static String getRandomStr(int length) {
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(3);
            long result;
            switch (number) {
                case 0:
                    result = Math.round(Math.random() * 25 + 65);
                    sb.append((char) result);
                    break;
                case 1:
                    result = Math.round(Math.random() * 25 + 97);
                    sb.append((char) result);
                    break;
                case 2:
                    sb.append(new Random().nextInt(10));
                    break;
            }
        }
        return sb.toString();
    }

    public static ByteBuf getByteBuf(byte[] bytes) {
        ByteBuf byteBuf = Unpooled.copiedBuffer(bytes);
        return byteBuf;
    }

    public static byte[] getByteArray(ByteBuf byteBuf) {
        int num = byteBuf.readableBytes();
        byte[] originalPacket = new byte[num];
        byteBuf.readBytes(originalPacket);

        return originalPacket;
    }

    public static byte[] append(byte[] first, byte[] back) {
        if (null == first || null == back) {
            return null;
        }
        int length = first.length + back.length;
        byte[] res = new byte[length];
        System.arraycopy(first, 0, res, 0, first.length);
        System.arraycopy(back, 0, res, first.length, back.length);
        return res;

    }

    public static byte[] short2Bytes(short number) {
        byte[] b = new byte[2];
        b[0] = (byte) (number >> 8);
        b[1] = (byte) (number & 0xff);
        return b;
    }

    public static byte[] int2bytes(int n) {
        byte[] b = new byte[4];

        for (int i = 0; i < 4; i++) {
            b[i] = (byte) (n >> (24 - i * 8));
        }
        return b;
    }

    public static String bytes2timeStr(byte[] array) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            int timeUnit = byte2UnsignedInt(array[i]);
            if (timeUnit < 10) {
                stringBuilder.append(0);
            }
            stringBuilder.append(timeUnit);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(new Date()).substring(0, 2) + stringBuilder.toString();
    }


    public static int byte2UnsignedInt(byte value) {
        return Byte.toUnsignedInt(value);
    }

    public static byte[] longToBytes(long num) {
        byte[] b = new byte[8];
        for (int i = 0; i < 8; i++) {
            b[i] = (byte) (num >>> (56 - i * 8));
        }
        return b;
    }

    public static long bytesToLong(byte[] b) {
        int mask = 0xff;
        long temp = 0;
        long res = 0;
        for (int i = 0; i < 8; i++) {
            res <<= 8;
            temp = b[i] & mask;
            res |= temp;
        }
        return res;
    }

    public static String bytes2bitStr(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder();
        for (byte b : bytes) {
            stringBuilder.append(byte2bitStr(b));
        }
        return stringBuilder.toString();
    }

    public static String byte2bitStr(byte b) {
        return "" + (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
                + (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1)
                + (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
                + (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
    }


    public static short bytes2Short(byte[] bytes) {
        short z = (short) ((bytes[0] << 8) | (bytes[1] & 0xFF));
        return z;
    }

    public static int bytes2int(byte[] data) {
        int mask = 0xff;
        int temp = 0;
        int n = 0;
        for (int i = 0; i < data.length; i++) {
            n <<= 8;
            temp = data[i] & mask;
            n |= temp;
        }
        return n;
    }

}
